package org.fujene.memman.backup;

import java.io.File;
import java.util.Date;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.fujene.memcon.MemoryController;

public class MemoryBackupService{
	private int interval;
	private MemoryController manager;
	private ConcurrentSkipListMap<Long, SnapShotStructure> backupList;
	private ExecutorService daemonSrv;
	private Thread daemon;

	public MemoryBackupService(int interval, MemoryController manager){
		this.interval = interval;
		if(interval == 0) this.interval = Integer.MAX_VALUE;
		this.manager = manager;
		this.backupList = new ConcurrentSkipListMap<Long, SnapShotStructure>();
		this.daemonSrv = Executors.newSingleThreadExecutor();
		this.daemon = new Thread(new SnapShotDaemon());
		this.daemon.setDaemon(true);
		this.daemonSrv.execute(daemon);
	}

	public void pickBackupData(){
		File thisDir = new File(".");
		File[] directories = thisDir.listFiles();

		for(File file: directories){
			String dirName = file.toString();
			if(file.isDirectory() && dirName.startsWith("backup_"))
				backupList.put(Long.parseLong(dirName.substring("backup_".length())),
					SnapShotStructure.fromFile(dirName));
		}
	}

	public void showList(){
		int index = 0;

		for(Entry<Long, SnapShotStructure> entries: backupList.entrySet())
			System.out.println(String.format("%5d Date:%s ID:%d ", (index++),
				new Date(entries.getKey()).toString(), entries.getKey())
				+ (entries.getValue().isToFile()? ("-> File"): ""));
	}

	public void toFileLatest(){
		String dirname = "backup_" + backupList.lastEntry().getKey().toString() + "/";
		backupList.lastEntry().getValue().setBackupToDisk(dirname);
		manager.doBackupToFile(backupList.lastEntry().getValue());
	}

	public void fromFileLatest(){
		for(Entry<Long, SnapShotStructure> latestItem: backupList.descendingMap().entrySet()){
			if(latestItem.getValue().isToFile()){
				try{
					manager.doRevertFromFile(latestItem.getKey().longValue());
				}catch(Exception e){
					e.printStackTrace();
				}
				break;
			}
		}
	}

	public void fromFileSpecified(long ID){
		SnapShotStructure item = backupList.get(Long.valueOf(ID));
		if(item != null){
			try{
				manager.doRevertFromFile(Long.valueOf(ID));
			}catch(Exception e){
				e.printStackTrace();
			}
		}
	}

	public void stop(){
		this.daemonSrv.shutdown();
		try{
			if(!this.daemonSrv.awaitTermination(5, TimeUnit.SECONDS)) this.daemonSrv.shutdownNow();
		}catch(InterruptedException e){
			this.daemonSrv.shutdownNow();
		}
	}

	public long addSnapshot(){
		SnapShotStructure structure = manager.copySnapshotData();
		backupList.put(Long.valueOf(System.currentTimeMillis()), structure);

		System.out.println("Added " + structure.ID() + " Entries: " + backupList.size());
		return structure.ID();
	}

	public void sync(){
		this.daemon.interrupt();
	}

	public long latestBackupIndex(){
		if(backupList.size() == 0) return -1;
		return backupList.lastKey().longValue();
	}

	private class SnapShotDaemon implements Runnable{
		@Override
		public void run(){
			while(true){
				try{
					TimeUnit.MINUTES.sleep(interval);
				}catch(InterruptedException ignored){
					break;
				}
				SnapShotStructure structure = manager.copySnapshotData();
				backupList.put(Long.valueOf(structure.ID()), structure);
			}
		}
	}
}
